package org.zhs.springframework.factory.support;

import cn.hutool.core.bean.BeanUtil;
import net.sf.cglib.proxy.Enhancer;
import org.zhs.springframework.BeansException;
import org.zhs.springframework.PropertyValue;
import org.zhs.springframework.PropertyValues;
import org.zhs.springframework.factory.config.BeanDefinition;
import org.zhs.springframework.factory.config.BeanReference;

import java.lang.reflect.Constructor;

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition,Object[] args) {
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition, beanName, args);

            //填充属性
            applyPropertyValues(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }
        registerSingleton(beanName, bean);
        return bean;
    }

    /**
     * 对象的属性填充
     * @param beanName
     * @param bean
     * @param beanDefinition
     */
    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition){
        try {
            //1.获取属性
            PropertyValues propertyValues = beanDefinition.getPropertyValues();
            //2.遍历属性
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {

                String name = propertyValue.getName();
                Object value = propertyValue.getValue();

                if(value instanceof BeanReference){
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }

                BeanUtil.setFieldValue(bean, name, value);
            }
        }catch (Exception e){
            throw new BeansException("Error setting property values:" + beanName);
        }
    }

    /**
     * 调用实例化方法，实例化对应的类
     * @param beanDefinition
     * @param beanName
     * @param args
     * @return
     */
    protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args){
        Constructor constructor = null;
        //1.获取当前类的class
        Class<?> beanClass = beanDefinition.getBeanClass();
        //2.获取当前类的所有构造方法
        Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
        //TODO
        //3.遍历所有构造方法，根据长度判断，此处有问题：比如如果参数长度一致，但是类型不一致（方法重载的情况）无法正常实例化
        for (Constructor ctor : declaredConstructors){
            if(null != args && ctor.getParameterTypes().length == args.length){
                constructor = ctor;
                break;
            }
        }
        return instantiationStrategy.instantiate(beanDefinition, beanName, constructor, args);
    }

    public InstantiationStrategy getInstantiationStrategy(){
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy){
        this.instantiationStrategy = instantiationStrategy;
    }
}
